﻿namespace Manhua2.Common
{
    using Manhua2.DataModel;
    using Manhua2.Provider;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.Networking.BackgroundTransfer;
    using Windows.Storage;

    public class DownloadManager
    {
        private static char[] invalid = Path.GetInvalidFileNameChars();

        private static List<DownloadOperation> actives = new List<DownloadOperation>();
        private static ObservableCollection<DownloadItem> items = new ObservableCollection<DownloadItem>();

        public static ObservableCollection<DownloadItem> CurrentDownloadItems
        {
            get { return DownloadManager.items; }
        }

        public static event EventHandler<DownloadItem> ItemCompleted;

        public static async Task AddToDownloads(DownloadItem item)
        {
            var check = items.Where(k => k.ComicTitle == item.ComicTitle &&
                                         k.ChapterTitle == item.ChapterTitle).FirstOrDefault();
            if (check != null)
                throw new ArgumentException("该章节已经在下载列表中");

            foreach (var ch in invalid)
            {
                if(item.ComicTitle.IndexOf(ch) != -1)
                    item.ComicTitle = item.ComicTitle.Replace(ch, '_');
            }
            
            // 添加到监控列表
            items.Add(item);

            // 创建目录， 目录规则 comic\chapter
            var folder = await Windows.Storage.DownloadsFolder.CreateFolderAsync(
                                    item.ComicTitle + "\\" + item.ChapterTitle,
                                    CreationCollisionOption.GenerateUniqueName);

            // 循环下载每一张漫画页
            int i = 1;
            foreach (var url in item.Urls)
            {
                var file = await folder.CreateFileAsync(
                                    i + Path.GetExtension(url),
                                    CreationCollisionOption.GenerateUniqueName);

                i++;

                var downloader = new BackgroundDownloader();
                var download = downloader.CreateDownload(new Uri(url), file);
                download.CostPolicy = BackgroundTransferCostPolicy.Default;
                item.Downloads.Add(download);
            }
        }

        public static async Task StartDownload(DownloadItem item)
        {
            if (item == null) return;

            try 
            {
                item.Status = "正在下载";

                foreach (var download in item.Downloads)
                {
                    try
                    {
                        await HandleDownloadAsync(download, true, item.CTS.Token);

                        item.CompletedPageCount++;
                    }
                    catch (TaskCanceledException)
                    {
                        throw;
                    }
                    catch (Exception)
                    {
                        item.FailedPageCount++;
                    }
                }

                item.Status = "下载完成";
            }
            catch(TaskCanceledException)
            {
                item.Status = "已取消";
            }

            if (ItemCompleted != null)
                ItemCompleted(null, item);
        }

        public static void PauseDownload(DownloadItem item)
        {
            foreach (var download in item.Downloads)
            {
                if (download.Progress.Status == BackgroundTransferStatus.Running)
                    download.Pause();
            }
        }

        public static void ResumeDownload(DownloadItem item)
        {
            foreach (var download in item.Downloads)
            {
                if (download.Progress.Status == BackgroundTransferStatus.PausedByApplication)
                {
                    download.Resume();
                }
            }
        }

        public static DownloadItem CreateDownloadItem(
            string comicTitle,
            string chapterTitle,
            int totalPage,
            IEnumerable<string> urls
            )
        {
            DownloadItem item = new DownloadItem()
            {
                ComicTitle = comicTitle,
                ChapterTitle = chapterTitle,
                TotalPageCount = totalPage,
            };

            foreach (var page in urls)
            {
                item.Urls.Add(page);
            }

            return item;
        }

        public async static Task<DownloadItem> CreateDownloadItemAsync(int chapterId)
        {
            using (DbContext context = new DbContext())
            {
                var chapter = await context.GetAsync<SQLiteTable.SQLiteChapter>(chapterId);
                var comic = await context.GetAsync<SQLiteTable.SQLiteComic>(chapter.ComicId);

                // 读取URL
                if (string.IsNullOrEmpty(chapter.Url))
                {
                    IComicProvider provider = ComicProviderFactory.Create(comic.Provider);
                    await provider.SaveChaptersAsync(comic.Id);
                    chapter = await context.GetAsync<SQLiteTable.SQLiteChapter>(chapterId);
                }

                // 获取所有页 pages
                // 如果pages为空, 启动获取章节所有页面地址的方法
                if (chapter.TotalPage == 0)
                {
                    IComicProvider provider = ComicProviderFactory.Create(comic.Provider);
                    await provider.SavePagesAsync(chapterId);
                    chapter = await context.GetAsync<SQLiteTable.SQLiteChapter>(chapterId);
                }

                var pages = await context.QueryPageUrlsAsync(chapter.Id);

                return CreateDownloadItem(comic.Title,
                                          chapter.Title,
                                          chapter.TotalPage,
                                          pages);
            }
        }

        private static async Task HandleDownloadAsync(DownloadOperation download, bool start, CancellationToken token)
        {
            try
            {
                actives.Add(download);

                if (start)
                {
                    await download.StartAsync().AsTask(token);
                }
                else
                {
                    await download.AttachAsync().AsTask(token);
                }
            }
            finally
            {
                actives.Remove(download);
            }
        }
    }
}
